﻿using Fast;
using Fast.Extensions;
using Fast.Extensions.EventBus;
using Fast.Extensions.EventBus.RabbitMQ;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Linq;

namespace Microsoft.AspNetCore.Builder
{
    [SkipScan]
    public static class EventBusRabbitMqApplicationBuilderExtensions
    {
        /// <summary>
        /// 添加事件总线
        /// </summary>
        /// <param name="app"></param>
        /// <param name="configure"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseEventBusWithRabbitMQ(this IApplicationBuilder app, Action<IEventBus> configure = default)
        {
            var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();

            //1.先订阅正常消息
            var handlerTypes = App.Types.Where(t => t.IsClass && t.IsPublic && !t.IsAbstract && !t.IsGenericType
                && t.HasImplementedTargetGeneric(typeof(IIntegrationEventHandler<>))).ToList();
            foreach (var handlerType in handlerTypes)
            {
                var eventType = handlerType.GetInterfaces()
                    .Where(i => i.GetGenericTypeDefinition() == typeof(IIntegrationEventHandler<>)).First()
                    .GetGenericArguments().First();

                typeof(IEventBus).GetMethod(nameof(IEventBus.Subscribe)).MakeGenericMethod(eventType, handlerType).Invoke(eventBus, null);
            }

            var options = app.ApplicationServices.GetRequiredService<IOptions<FastRabbitMqEventBusOptions>>().Value;
            if (options.EnableDeadLetterExchange.Value)
            {
                //2.后订阅异常消息，顺序不能颠倒，否则会出现死信队列还未创建就消费的情况
                var exceptionHandlerTypes = App.Types.Where(t => t.IsClass && t.IsPublic && !t.IsAbstract && !t.IsGenericType
                    && t.HasImplementedTargetGeneric(typeof(IIntegrationEventExceptionHandler<>))).ToList();
                foreach (var exceptionHandlerType in exceptionHandlerTypes)
                {
                    var eventType = exceptionHandlerType.GetInterfaces()
                        .Where(i => i.GetGenericTypeDefinition() == typeof(IIntegrationEventExceptionHandler<>)).First()
                        .GetGenericArguments().First();

                    typeof(IEventBus).GetMethod(nameof(IEventBus.SubscribeException)).MakeGenericMethod(eventType, exceptionHandlerType).Invoke(eventBus, null);
                }
            }

            configure?.Invoke(eventBus);

            return app;
        }
    }
}
